<?php 
/**
* Format text according to BBCdore tags.
*The following BBCode tags are supported:
*- [b]text[/b] - Bold text.
*- [i]text[/i] - Italic text.
*- [u]text[/u] - Underlined text (using CSS text-decoration).
*- [s]text[/s] - Strike-trough text (using CSS text-decoration).
*- [code]text[/code] - print code (using a div with class "code").
*- [quote]text[/quote] - print a quotation (using p with class "quote").
*- [quote=name]text[/quote] - print a named quotation (using p with class "quote" and span with class "quote").
*- [size=Y]text[/size] - Set font-size. Y is expressed in points (pt). Uses a styled span
*- [color=F]text[/color] - Set tetx color. Uses span with styles.
*- [ul]xxx[/ul] - Unnumbered list.
*- [ol]xxx[/ol] - Numbered list.
*- [li]text[/li] - List item.
*- [p]text[/p] - Paragraph.
*- [center]ytext[/center] - Center text. Uses p with style.
*- [url]url[/url] - make a link
*- [url=xxx]text[/url] - make a nicer link
*- [img]xxx[/img] - Show an image. NOTE: images are only read from storage area.
*
*The following extra tags are supported:
*- [align=center|left|right]text[/align] - Align text. Uses p with style.
*- [color=F,B]text[/color] - Set text foreground and background color. Uses span with style.
*- [list]xxx[/list] - Backward compatibility. Same as [ul].
*- [h1-6]text[/h1-6] - Headers (h1 trough h6). Uses h1-h6 tags.
*- [extlink=xxx]text[/extlink] - Backward compatible. Same as [url=].
*- [hide]text[/hide] - Hide something. Useful to put some text in place to show at later time. Code is not printed.
*- [storage=xx]text[/storage] - A link to a storage file.

*@package Html
*@author Willy Gardiol <willy@gardiol.org>
*@version 1.0
*/
class HtmlBBCode extends HtmlTag
{
	static private $valid_codes = array(
			'/(\[b\])(.+?)(\[\/b\])/', # [b][/b] => <b></b>
			'/(\[i\])(.+?)(\[\/i\])/', # [i][/i] => <i></i>
			'/(\[u\])(.+?)(\[\/u\])/', # [u][/u] => <span style=text-decoration:underline;"></span>
			'/(\[s\])(.+?)(\[\/s\])/', # [s][/s] => <span style=text-decoration:line-through;"></span>
			'/(\[code\])(.+?)(\[\/code\])/', # [code][/code] => <div class="code"></div>
			'/(\[quote\])(.+?)(\[\/quote\])/', # [quote][/quote] => <p class="quote"></p>
			'/(\[quote=)(.+?)(\])(.+?)(\[\/quote\])/', #[quote=name][/quote] => <p class="quote">name: text</p>
			'/(\[size=)(.+?)(\])(.+?)(\[\/size\])/', #[size=s][/size] => <span style=font-size:spt;"></span>
			'/(\[color=)([^,\]]+?)(,)(.+?)(\])(.+?)(\[\/color\])/', #[color=F,B][/color] => <span style=color:F;background:B"></span>
			'/(\[color=)(.+?)(\])(.+?)(\[\/color\])/', #[color=c][/color] => <span style=color:c;"></span>
			'/(\[list\])(.+?)(\[\/list\])/', #[list][/list] => <ul></ul>
			'/(\[ul\])(.+?)(\[\/ul\])/', #[ul][/ul] => <ul></ul>
			'/(\[ol\])(.+?)(\[\/ol\])/', #[ol][/ol] => <ol></ol>
			'/(\[li\])(.+?)(\[\/li\])/', #[li][/li] => <li></li>
			'/(\[p\])(.*?)(\[\/p\])/', # [p][/p] => <p></p>
			'/(\[align=)(.+?)(\])(.+?)(\[\/align\])/', #[align=what][/align] => <p style="text-align:what></p>
			'/(\[center\])(.+?)(\[\/center\])/', #[center][/center] => <p style="text-align:center></p>
			'/(\[h)([123456])(\])(.+?)(\[\/h\\2\])/', # [h1-6][/h1-6] => <i></i>
			'/(\[url\])(.*?)(\[\/url\])/',
			'/(\[url=)(.+?)(\])(.*?)(\[\/url\])/',
			'/(\[extli?nk[=;])(.*?)(\])(.*?)(\[\/extli?nk\])/',
			'/(\[hide\])(.*?)(\[\/hide\])/',
						);
	static private $valid_replace = array (
			'<b>\\2</b>',
			'<i>\\2</i>',
			'<span style="text-decoration:underline;">\\2</span>',
			'<span style="text-decoration:line-through;">\\2</span>',
			'<div class="code">\\2</div>',
			'<p class="quote"><i>\\2</i></p>',
			'<p class="quote"><span class="quote">\\2:</span><i>\\4</i></p>',
			'<span style="font-size:\\2pt;">\\4</span>',
			'<span style="color:\\2;background:\\4;">\\6</span>',
			'<span style="color:\\2;">\\4</span>',
			'<ul>\\2</ul>',
			'<ul>\\2</ul>',
			'<ol>\\2</ol>',
			'<li>\\2</li>',
			'<p>\\2</p>',
			'<p style="text-align: \\2;">\\4</p>',
			'<p style="text-align: center;">\\2</p>',
			'<h\\2>\\4</h\\2>',
			'<a href="\\2">\\2</a>',
			'<a href="\\2">\\4</a>',
			'<a href="\\2">\\4</a>',
			'',
							);

	private function ProcessStorage( $string )
	{
		$start_pos = 0;
		# Find the open tag
		while ( ( $start_pos = strpos( $string, "[storage=", $start_pos ) ) !== false )
		{	# Adjust start position to ignore the [storage= part of the tag
			$start_pos += 9;
			# Read the close tag
			if ( ($end_pos = strpos( $string, "[/storage]", $start_pos)) !== false )
			{	# Ok, the tag is complete.. lets find where the ID ends...
				$id_end = strpos($string,"]",$start_pos);
				# Read the ID
				$id = substr( $string, $start_pos, $id_end-$start_pos );
				# Get the storage object... (if none, ignore the tag)
				if ( ( $stored_obj = Storage::Get( $id )) !== false )
				{	# Ok, the ID reflects a valid object... build the HTML tag
					$text = "<a href='$stored_obj'>".substr( $string, $id_end+1, $end_pos-$id_end-1 )."</a>";
					# Substitute the tag into the string
					$tmp = substr($string, 0, $start_pos-9).$text.substr($string, $end_pos+10);
					$string = $tmp;
				}
			}
		}
		return $string;
	}
	private function ProcessImg( $string )
	{
		$start_pos = 0;
		# Find the open tag
		while ( ( $start_pos = strpos( $string, "[img]", $start_pos ) ) !== false )
		{
			$start_pos += 5;
			# Read the close tag
			if ( ($end_pos = strpos( $string, "[/img]", $start_pos)) !== false )
			{	# Ok the tag is complete, read the ID
				$id = substr( $string, $start_pos, $end_pos-$start_pos );
				# Get the storage object... (if none, ignore the tag)
				if ( ( $stored_obj = Storage::Get( $id )) !== false )
				{	# Build the HTML tag
					$text = "<img src='$stored_obj' />";
					# Substitute it in the string
					$tmp = substr($string, 0, $start_pos-9).$text.substr($string, $end_pos+10);
					$string = $tmp;
				}
			}
		}
		return $string;
	}

	private $text = "";
	public function __construct( $text )
	{
		parent::__construct("span");
		$this->text = $text;
	}
	# Replace parent __tostring...
	public function __tostring()
	{
		# We need to escape all newlines first or preg_replace will not work properly!
		$code = str_replace( array("\r","\n"), array("|*&","%|&"), $this->text );
		# Replace all basic bbcode tags...
		$code = preg_replace( HtmlBBCode::$valid_codes, HtmlBBCode::$valid_replace, $code );
		# Replace special tags...
		$code = $this->ProcessStorage( $code );
		$code = $this->ProcessImg( $code );
		# Put back newlines...
		$code = str_replace( array("|*&","%|&"),array("\r","\n"), $code );
		return $code;
	}
}
?>